<template>
  <div class="container">
    <!-- 顶部卡片 -->
    <el-card class="top-card">
      <div class="top-content">
        <div class="user-info">
          <img :src="avatarSrc" class="avatar" />
          <div class="welcome-text">
            <p class="username">你好，{{ userInfo.name }}</p>
            <el-tooltip :content="greeting_transl" placement="bottom" effect="light">
              <p class="greeting">{{ greeting }}</p>
            </el-tooltip>
          </div>
        </div>
        <div class="stats">
          <div v-for="(item, index) in stats" :key="index" class="stat-item">
            <div class="value">
              {{ item.value === 9998 ? "--" : item.value === 9999 ? "假期" : item.value }}
            </div>
            <div class="label">{{ item.label }}</div>
          </div>
        </div>
      </div>
    </el-card>

    <div class="main-content">
      <!-- 左侧区域 -->
      <div class="left-side">
        <!-- 消息栏 -->
        <el-card class="message-box">
          <div class="message-header">
            <span>消息</span>
            <el-button type="primary" link @click="handleMessageClick">查看全部 >></el-button>
          </div>
          <ul class="message-list" v-if="messages.length > 0">
            <li v-for="(msg, index) in messages" :key="index" class="message-item">
              {{ msg }}
            </li>
          </ul>
          <div v-else>
            <div style="text-align: center; color: #999; margin-top: 100px">暂无消息</div>
          </div>
        </el-card>

        <!-- 日历 -->
        <el-card class="calendar-box">
          <div class="message-header">
            <span>今日课程</span>
            <span class="current-date" style="cursor: pointer" @click="resetToToday">
              {{ selectedDate.toLocaleDateString() }}
              <el-tooltip content="点击返回今天" placement="top" effect="light">
                <el-icon><Calendar /></el-icon>
              </el-tooltip>
            </span>
            <el-button type="primary" link @click="handleCalendarClick">查看全部 >></el-button>
          </div>
          <div class="week-days">
            <div
              v-for="(day, index) in weekDays"
              :key="index"
              class="day"
              :class="{ today: day.isToday, selected: day.isSelected }"
              @click="handleDateClick(day.fullDate)"
              style="cursor: pointer"
            >
              <div class="date">{{ day.date }}</div>
            </div>
          </div>
          <div class="today-schedule" v-if="todayCourses.length > 0">
            <div class="schedule-item" v-for="item in todayCourses" :key="item.time">
              <span class="time">{{ item.time }}</span>
              <span class="name">{{ item.name.length > 10 ? item.name.slice(0, 10) + "..." : item.name }}</span>
              <span class="classroom">{{ item.classroom }}</span>
            </div>
          </div>
          <div v-else-if="!is_now_table">
            <div style="text-align: center; color: #999; margin-top: 100px">
              还未获取<a :href="`/myCourse?y=${year_term.year}&s=${year_term.semester}`"
                >{{ year_term.year }}-{{ parseInt(year_term.year) + 1 }}学年第{{ year_term.semester }}学期</a
              >课程表
            </div>
          </div>
          <div v-else>
            <div style="text-align: center; color: #999; margin-top: 100px">今日无课程</div>
          </div>
        </el-card>
      </div>

      <!-- 右侧图表 -->
      <div class="right-side">
        <el-carousel
          :interval="10000"
          indicator-position="inside"
          class="chart-carousel"
          @change="handleCarouselChange"
        >
          <el-carousel-item v-for="(_, index) in charts" :key="index">
            <el-card class="chart-card">
              <!-- <h3 class="chart-title">{{ JSON.stringify(chart).slice(0, 50) }}</h3> -->
              <el-button @click="mainDialogVisible = true" link type="primary">查看成绩>></el-button>
              <div
                class="chart-container"
                :ref="
                  el => {
                    if (el) chartRefs[index] = el;
                  }
                "
              ></div>
            </el-card>
          </el-carousel-item>
        </el-carousel>
      </div>
    </div>
  </div>

  <el-dialog v-model="mainDialogVisible" width="50%" center>
    <!-- 主对话框 -->
    <template #header>
      <div class="dialog-header">
        <span>成绩信息</span>
        <el-button type="primary" @click="gpaDialogVisible = true" link>学分绩点预览</el-button>
        <el-button type="primary" @click="showUpdateDialog" :icon="Refresh" circle />
      </div>
    </template>

    <!-- 学期筛选 -->
    <div class="filter-container">
      <el-select v-model="selectedTerm" placeholder="请选择学期">
        <el-option label="全部学期" value="all" />
        <el-option v-for="term in uniqueTerms" :key="term" :label="term" :value="term" />
      </el-select>
    </div>

    <!-- 课程表格 -->
    <div class="table-container">
      <template v-for="(group, type) in filteredCourses" :key="type">
        <h3 class="group-title" v-if="group.length > 0">{{ typeMap[type] }}</h3>
        <el-table
          :data="group"
          stripe
          :row-class-name="tableRowClassName"
          :header-cell-style="{
            position: 'sticky',
            top: '40px',
            zIndex: '1',
            background: '#fff'
          }"
          v-if="group.length > 0"
        >
          <el-table-column prop="code" label="课程代码" width="120" sortable align="center" />
          <el-table-column prop="name" label="课程名称" align="center" />
          <el-table-column prop="time" label="学期" width="180" sortable align="center" />
          <el-table-column prop="grade" label="成绩" width="120" sortable align="center">
            <template #default="{ row }">
              <span :class="gradeClass(row.grade)">{{ row.grade }}</span>
            </template>
          </el-table-column>

          <template #empty>
            <div style="text-align: center; color: #999; margin-top: 100px">暂无数据</div>
          </template>
        </el-table>
      </template>
    </div>

    <!-- 更新对话框 -->
    <el-dialog v-model="updateDialogVisible" title="获取个人成绩" width="30%" append-to-body center>
      <el-form :model="loginForm" ref="loginFormRef" style="padding: 0 20px">
        <el-form-item label="学号" prop="studentId">
          <el-input v-model="loginForm.studentId" autocomplete="off" :readonly="true" />
        </el-form-item>
        <el-form-item>
          <el-checkbox v-model="loginForm.hardUpdate">强制更新</el-checkbox>
          <el-checkbox v-model="loginForm.remember" v-if="loginForm.hardUpdate">记住密码</el-checkbox>
          <el-space fill style="width: 100%; margin-top: 10px" v-if="loginForm.hardUpdate">
            <el-alert type="info" :closable="false" size="small">
              <div class="declaration-content">
                <div class="declaration-section">
                  <h4>数据缓存及使用声明</h4>
                  <ol class="declaration-list">
                    <li>
                      <p>授权数据范围及用途：</p>
                      <div class="usage-items">
                        <div class="usage-item">
                          <span class="highlight">课表数据</span>
                          <span class="usage-desc">用于无课表生成、课表规划、课程推荐</span>
                        </div>
                        <div class="usage-item">
                          <span class="highlight">成绩数据</span>
                          <span class="usage-desc">用于课程通过率分析（课程代码/名称、教师名称、成绩等级）</span>
                        </div>
                      </div>
                    </li>
                    <li>
                      <p>信息安全承诺：</p>
                      <ul class="security-list">
                        <li>不存储MySeig系统登录凭据（密码等敏感信息仅用于当次认证）</li>
                        <li>认证参数进行对称加密传输</li>
                        <li>不向第三方披露任何MySeig系统原始数据</li>
                        <li>统计分析采用不可逆脱敏处理（提取关键字段，不可溯源）</li>
                      </ul>
                    </li>
                  </ol>
                </div>
                <div class="declaration-section">
                  <h4>注意</h4>
                  <p>
                    <span class="highlight">记住密码</span>功能仅将MySeig系统密码加密后存储于浏览器本地。 启用<span
                      class="highlight"
                      >强制更新</span
                    >后，平台将直接从MySeig系统获取相关数据， 否则为读取后台数据库中的缓存数据。
                  </p>
                </div>
              </div>
            </el-alert>
          </el-space>
        </el-form-item>
        <el-form-item label="密码" prop="password" v-if="loginForm.hardUpdate">
          <el-input
            v-model="loginForm.password"
            type="password"
            show-password
            autocomplete="new-password"
            placeholder="MySeig系统密码"
          />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="updateDialogVisible = false">取消</el-button>
        <el-button type="primary" @click="handleUpdate">确认</el-button>
      </template>
    </el-dialog>

    <el-dialog v-model="gpaDialogVisible" width="50%" center title="学分绩点预览">
      <!-- 绩点 -->
      <div class="gpa-container">
        <div class="course-list">
          <!-- 按学期分组 -->
          <div v-for="semester in getSemesterGroups()" :key="semester" class="semester-group">
            <el-tooltip
              content="输入或选择预期课程成绩可预测绩点，绩点计算依据于本校绩点计算规则，有待完善，仅供参考"
              placement="top"
              effect="light"
            >
              <div class="semester-header">{{ semester }} 绩点预测</div>
            </el-tooltip>
            <div v-for="course in getSemesterCourses(semester)" :key="course.name" class="course-item">
              <div class="course-info">
                <el-tag
                  size="small"
                  :type="course.grade === '在读' ? 'primary' : 'info'"
                  style="font-size: 10px; margin-right: 5px"
                >
                  {{ course.grade === "在读" ? "在读" : "未修" }}
                </el-tag>
                <span class="course-name">{{ course.name }}</span>
                <el-tag size="small" type="success" effect="plain" class="course-credit">{{ course.crd }} 学分</el-tag>
              </div>
              <el-select
                v-model="course.grade"
                placeholder="选择成绩"
                class="course-input"
                @change="updateTempGPA"
                v-if="course.kao === '考查'"
              >
                <el-option label="优" value="优"></el-option>
                <el-option label="良" value="良"></el-option>
                <el-option label="中" value="中"></el-option>
                <el-option label="及格" value="及格"></el-option>
                <el-option label="不及格" value="不及格"></el-option>
              </el-select>
              <el-input
                v-model="course.grade"
                placeholder="输入成绩"
                class="course-input"
                @change="updateTempGPA"
                v-else
              />
            </div>
          </div>
        </div>
        <div class="gpa-value">
          GPA:<span v-if="tempGPA > oldGPA" class="gpa-change gpa-up">+{{ (tempGPA - oldGPA).toFixed(2) }}=</span
          ><span v-else-if="tempGPA < oldGPA" class="gpa-change gpa-down">-{{ (oldGPA - tempGPA).toFixed(2) }}=</span>
          {{ tempGPA }} ≈ {{ parseFloat(tempGPA.toFixed(1)).toFixed(1) }}
          <div style="color: #f56c6c; font-size: 12px; margin-top: 5px">
            注意：挂科/无成绩将无法获得学分且不计入绩点计算
            <span style="cursor: pointer; color: #409eff" @click="refreshGPA">重置</span>
          </div>
        </div>
      </div>
      <!-- 学分公式展示 -->
      <div class="credit-container">
        <div class="credit-formula">
          <div class="formula-title">剩余选修学分</div>
          <div class="formula-content">
            <el-tooltip content="您毕业所需总学分" placement="top" effect="light">
              <span class="formula-item total-crd">{{ personalData.parse_crd?.total_crd || 0 }}</span>
            </el-tooltip>
            <span class="formula-operator">-</span>
            <el-tooltip placement="top" effect="light">
              <template #content>
                <div class="tooltip-formula">
                  已修学分 = 已获得学分 + 挂科学分
                  <div class="sub-formula">
                    <span class="earned">{{ personalData.parse_crd?.earned_crd || 0 }}</span> =
                    <span class="passed">{{ obtainedCredits }}</span> +
                    <span class="failed">{{ failedCredits }}</span>
                  </div>
                </div>
              </template>
              <span class="formula-item earned-crd">{{ personalData.parse_crd?.earned_crd || 0 }}</span>
            </el-tooltip>
            <span class="formula-operator">-</span>
            <el-tooltip content="当前在读课程总学分" placement="top" effect="light">
              <span class="formula-item studying-crd">{{ personalData.parse_crd?.studying_crd || 0 }}</span>
            </el-tooltip>
            <span class="formula-operator">-</span>
            <el-tooltip content="未修必修/选修(专业限选课)课总学分" placement="top" effect="light">
              <span class="formula-item notrepaired-crd">{{ unstudiedCredits }}</span>
            </el-tooltip>
            <span class="formula-operator">=</span>
            <el-tooltip content="仍需选修的剩余学分" placement="top" effect="light">
              <span class="formula-item remain-crd">{{ calculateRemainCrd }}</span>
            </el-tooltip>
          </div>
        </div>
      </div>
    </el-dialog>
  </el-dialog>
</template>

<script setup lang="ts">
  import { ref, onMounted, onBeforeUnmount, nextTick, computed, watch } from "vue";
  import { ElLoading, ElMessage } from "element-plus";
  import * as echarts from "echarts";
  import { useRouter } from "vue-router";
  import api from "../axios/api";
  // @ts-ignore
  import multiavatar from "@multiavatar/multiavatar";
  import { encrypt, decrypt } from "../utils/crypto";
  import { Refresh, Calendar } from "@element-plus/icons-vue";

  const greeting = ref("正在加载今日诗词....");
  const greeting_transl = ref("");

  const getGreeting = async () => {
    try {
      // throw new Error('test')
      const t_res = await api.getTodayGreeting();
      greeting.value = `${t_res.data.result.saying}—— ${t_res.data.result.source}`;
      greeting_transl.value = t_res.data.result.transl;
    } catch (error) {
      console.log(error);
      greeting.value = "今天又是元气满满的一天！";
      greeting_transl.value = "Today is another day of full of energy!";
    }
  };

  const router = useRouter();
  const handleMessageClick = () => {
    // 跳转到消息页面
    router.push("/myorganization");
  };

  const handleCalendarClick = () => {
    // 跳转到课程表页面
    router.push("/myCourse");
  };

  /** 用户信息（优先从 localStorage 中获取，如不存在则默认'靓仔'） */
  const userInfo = ref({
    name: JSON.parse(localStorage.getItem("userInfo") || "{}").name || "靓仔"
  });

  /** 消息列表 */
  const messages = ref([]);
  const week_num = ref(0);
  /** 统计数据 */
  const stats = ref([
    { label: "教学周", value: 0 },
    { label: "组织", value: 2 },
    { label: "消息", value: messages.value.length }
  ]);

  // 定义今日课程类型
  interface Course {
    time: string;
    name: string;
    classroom: string;
  }
  const todayCourses = ref<Course[]>([]);

  // 获取数据
  const getData = async () => {
    const orgResponse = await api.getOrganizationList(localStorage.getItem("userId"));
    const orgLen = orgResponse.data.length;
    const msgResponse = await api.getMsgList(localStorage.getItem("userId"));
    const msgList = msgResponse.data;
    const msgLen = msgList.filter(
      (msg: any) => (msg.type === "Ta申请加入我" || msg.type === "Ta邀请我加入") && msg.status === "pending"
    ).length;
    stats.value[1].value = orgLen;
    stats.value[2].value = msgLen;
    messages.value = msgList
      .filter((msg: any) => (msg.type === "Ta申请加入我" || msg.type === "Ta邀请我加入") && msg.status === "pending")
      .map((msg: any) => msg.type.replace("Ta", msg.personal_info.name + " ") + "组织：" + msg.org_info.org_name);
    // console.log(messages.value)
    getTodayCourses1();
  };
  // const today = new Date('2025-03-03')
  const today = new Date();
  const tableData = ref(JSON.parse(localStorage.getItem("tableData") || "{}"));
  const courseTeacherMap: Record<string, string> = {};
  const is_now_table = computed(() => {
    if (tableData.value.length > 0) {
      return tableData.value.some(
        (table: any) =>
          table.year_term.year === year_term.value.year && table.year_term.semester === year_term.value.semester
      );
    } else {
      return false;
    }
  });

  const getYearAndSemester = () => {
    let year = today.getFullYear();
    const month = today.getMonth() + 1; // getMonth() 返回的月份是从0开始的，所以需要加1
    let semester;
    if (month >= 9 && month <= 12) {
      semester = 1;
      // } else if (month >= 1 && month <= 8) {
      //   year -= 1
      //   semester = 2
    } else {
      year -= 1;
      semester = 2;
    }
    // year = 2021 ///////////////////////////////////////////////////////////////////////////////////////////////////
    return { year: year.toString(), semester: semester.toString() };
  };
  const year_term = ref(getYearAndSemester());
  const selectedDate = ref(new Date()); // 新增：选中日期的状态变量

  const getTodayCourses1 = () => {
    if (tableData.value.length > 0) {
      const now_table = tableData.value.filter(
        (item: any) =>
          item.year_term.year === year_term.value.year && item.year_term.semester === year_term.value.semester
      );
      tableData.value.forEach((term: any) =>
        term.schedules?.forEach((schedule: any) =>
          (["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"] as const).forEach(day => {
            const courses = schedule[day];
            Array.isArray(courses) &&
              courses.forEach(
                c => c.course_name && c.course_teacher && (courseTeacherMap[c.course_name] = c.course_teacher)
              );
          })
        )
      );
      // console.log(courseTeacherMap)
      if (now_table.length > 0) {
        const week_start_date = now_table[0].week_info.week_start_date.replace(/年|月/g, "-").replace("日", "");
        // 计算当前时间是第几教学周
        week_num.value = Math.ceil(
          (today.getTime() - new Date(week_start_date).getTime() + 1) / (7 * 24 * 60 * 60 * 1000)
        );
        stats.value[0].value = week_num.value;
        todayCourses.value = getTodayCourses2(selectedDate.value, now_table[0]);
        // console.log(todayCourses.value)
      } else {
        stats.value[0].value = 9999;
      }
    } else {
      stats.value[0].value = 9998;
    }
  };
  const getTodayCourses2 = (today: Date, nowTable: any) => {
    // 解析周开始日期

    const parseChineseDate = (dateStr: string) => {
      const [year, month, day] = dateStr.match(/\d+/g)?.map(Number) || [];

      return new Date(year, month - 1, day);
    };
    const weekStartDate = parseChineseDate(nowTable.week_info.week_start_date);

    // 计算当前周数
    const diffTime = today.getTime() - weekStartDate.getTime();
    const diffDays = Math.floor(diffTime / (1000 * 3600 * 24));
    const weekNumber = Math.floor(diffDays / 7) + 1;

    // 获取星期几
    const days = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"];
    const dayOfWeek = days[today.getDay()];

    // 收集课程
    const courses = [];
    for (const schedule of nowTable.schedules) {
      const timeSlot = schedule.time;
      const dailyCourses = schedule[dayOfWeek];
      if (!dailyCourses || dailyCourses.length === 0) continue;

      for (const course of dailyCourses) {
        const validRooms = course.course_week_room
          .filter((cwr: any) => cwr.course_weeks.includes(weekNumber.toString()))
          .map((cwr: any) => cwr.course_room);

        if (validRooms.length > 0) {
          courses.push({
            name: course.course_name,
            time: timeSlot.split("\n")[1],
            classroom: validRooms.join(", ")
          });
        }
      }
    }
    return courses;
  };

  function generateWeekDays() {
    const days = [];

    // 计算今天在周中的位置（若周日，则认为是第7天）
    const dayOfWeek = today.getDay() === 0 ? 7 : today.getDay();
    const monday = new Date(today);
    monday.setDate(today.getDate() - dayOfWeek + 1);
    for (let i = 0; i < 7; i++) {
      const date = new Date(monday);
      date.setDate(monday.getDate() + i);
      days.push({
        date: date.getDate(),
        fullDate: new Date(date), // 存储完整日期对象
        isToday: date.toDateString() === today.toDateString(),
        isSelected: date.toDateString() === selectedDate.value.toDateString()
      });
    }
    return days;
  }
  const weekDays = ref(generateWeekDays());

  /** 图表相关：图表容器引用数组及图表配置数据 */
  const chartRefs = ref<any[]>([]);
  const charts = ref<{ title: string; data: any }[]>([
    { title: "课程评分等级分布", data: [] },
    { title: "绩点贡献度分析", data: [] },
    { title: "课程评分等级分布", data: [] },
    { title: "绩点贡献度分析", data: [] }
  ]);

  /** ECharts实例集合 */
  let chartInstances: echarts.ECharts[] = [];

  /** 通用图表配置函数（饼图） */
  const getPieChartOption = (title: string, data: { name: string; value: number }[]) => ({
    title: {
      text: title,
      left: "center"
    },
    tooltip: {
      trigger: "item",
      formatter: (params: any) => {
        return `
          <div>
            <strong style="font-size:15px; display:block; text-align:center; margin-bottom:5px;">${params.name}</strong>
            <div style="text-align:center; margin-bottom:8px;">
              （${
                params.name === "优秀"
                  ? "90-100"
                  : params.name === "良好"
                  ? "80-89"
                  : params.name === "中等"
                  ? "70-79"
                  : params.name === "及格"
                  ? "60-69"
                  : params.name === "不及格"
                  ? "0-59"
                  : "未知"
              }）
              <span style="color:${params.color}">●&nbsp;</span> 
              数量：${params.value}&nbsp;&nbsp;
              <span>占比：${params.percent}%</span>
            </div>
            <div style="color:#aaa; border-top:1px solid #eee; padding-top:5px;">
              ${getCourseNameByGrade(params.name)}
            </div>
          </div>
        `;
      },
      enterable: true,
      confine: true,
      appendToBody: true,
      extraCssText: "box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1); border-radius: 6px; padding:10px;",
      rich: {
        course: {
          color: "#aaa",
          fontSize: 12
        }
      }
    },
    legend: [
      {
        orient: "vertical", // 改为垂直布局
        top: "60%",
        left: "left",
        data: data.slice(Math.ceil(data.length / 2)).map(item => item.name)
      },
      {
        orient: "vertical",
        top: "60%",
        right: "left",
        data: data.slice(0, Math.ceil(data.length / 2)).map(item => item.name)
      }
    ],
    series: [
      {
        name: title,
        type: "pie",
        radius: ["40%", "75%"],
        data: data,
        label: {
          formatter: "{b}: {c} ({d}%)"
        },
        itemStyle: {
          borderRadius: 10,
          borderColor: "#fff",
          borderWidth: 2,
          borderJoin: "round",
          color: (params: any) => {
            const colorList = [
              "#4DAB8F",
              "#8FB79D",
              "#EDDDC3",
              "#FC8C5A",
              "#DA4E33",
              "#7986CB",
              "#A1887F",
              "#E57373",
              "#AED581",
              "#4DB6AC",
              "#DCE775",
              "#FFF176",
              "#BA68C8",
              "#64B5F6",
              "#F06292"
            ];
            return colorList[params.dataIndex % colorList.length];
          }
        },
        emphasis: {
          itemStyle: {
            shadowBlur: 10,
            shadowOffsetX: 0,
            shadowColor: "rgba(0, 0, 0, 0.5)"
          }
        }
      }
    ]
  });
  /** 条形图配置函数 */
  const getBarChartOption = (title: string, data: any) => {
    // 处理数据
    const courses = Object.keys(data).reverse();
    const values = Object.entries(data)
      .map(([name, info]: any) => ({
        value: info.影响因子,
        学分: info.学分,
        绩点: info.绩点,
        成绩: info.成绩,
        说明: info.说明,
        总学分: info.总学分,
        name: name
      }))
      .reverse();

    // 获取影响因子绝对值最大值
    const maxImpactFactor = Math.max(...values.map(item => Math.abs(item.value))) * 1.2;

    // 处理学期背景数据
    const semesters = courses.map(course => data[course].学期);
    const semesterRanges: any[] = [];
    let currentSemester = semesters[0];
    let startIdx = 0;

    // 生成合并后的学期区间
    for (let i = 1; i < semesters.length; i++) {
      if (semesters[i] !== currentSemester) {
        semesterRanges.push({
          start: startIdx,
          end: i - 1,
          semester: currentSemester
        });
        currentSemester = semesters[i];
        startIdx = i;
      }
    }
    semesterRanges.push({
      start: startIdx,
      end: semesters.length - 1,
      semester: currentSemester
    });

    // 交替背景色配置
    const backgroundColors = [
      "rgba(97, 145, 195, 0.9)", // 深蓝色
      "rgba(144, 238, 144, 0.9)" // 深绿色
    ];

    return {
      title: {
        text: title,
        left: "center"
        // top: 10,
      },
      tooltip: {
        trigger: "item",
        formatter: function (params: any) {
          const data = params.data;
          return `<div style="
                padding: 6px;
                font-size: 12px;
                background: #fff;
            ">
                <div style="font-weight:600;margin-bottom:4px;text-align:center;min-width:120px;">${params.name}</div>
                
                <table style="width:100%;border-collapse:collapse;">
                    <tr>
                        <td style="padding:2px 0;color:#666;text-align:left;">教师</td>
                        <td style="padding:2px 0;text-align:right;">${courseTeacherMap[params.name] || "—"}</td>
                    </tr>
                    <tr>
                        <td style="padding:2px 0;color:#666;text-align:left;">学分</td>
                        <td style="padding:2px 0;color:#2e7d32;text-align:right;">${data.学分}</td>
                    </tr>
                    <tr>
                        <td style="padding:2px 0;color:#666;text-align:left;">成绩</td>
                        <td style="text-align:right;">${data.成绩}</td>
                    </tr>
                    <tr>
                        <td style="padding:2px 0;color:#666;text-align:left;">课程绩点</td>
                        <td style="color:#1976d2;text-align:right;">${data.绩点}</td>
                    </tr>
                    <tr>
                        <td style="padding:2px 0;color:#666;text-align:left;">影响因子</td>
                        <td style="color:${
                          data.value > 0 ? "#5470C6" : "#EE6666"
                        };text-align:right;">${data.value.toFixed(4)}</td>
                    </tr>
                </table>
            </div>`;
        },
        enterable: true,
        confine: true,
        appendToBody: true,
        extraCssText: "box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1); border-radius: 6px; padding:10px;"
      },
      grid: {
        left: "5%",
        right: "15%", // 调整右侧空间
        containLabel: true
      },
      dataZoom: [
        // 数据缩放
        {
          type: "slider",
          show: true,
          yAxisIndex: [0],
          left: "98%",
          start: 0,
          end: Math.min(100, Math.max(1000 / courses.length, 30)),
          filterMode: "empty",
          width: 10,
          height: "80%",
          showDataShadow: false,
          borderColor: "transparent"
        },
        {
          type: "inside",
          yAxisIndex: [0],
          zoomLock: false,
          zoomOnMouseWheel: "ctrl",
          moveOnMouseWheel: true,
          moveOnMouseMove: true,
          preventDefaultMouseMove: false,
          throttleRate: 20,
          start: 0,
          end: 100
        }
      ],
      yAxis: {
        type: "category",
        name: "",
        data: courses,
        axisLabel: {
          fontSize: 12,
          width: 100,
          overflow: "truncate",
          interval: 0
        },
        axisTick: {
          alignWithLabel: true
        }
      },
      xAxis: {
        type: "value",
        name: "影响因子（负数为拉低，正数为提升）",
        nameLocation: "center",
        nameTextStyle: {
          fontSize: 12,
          padding: [20, 0, 0, 0]
        },
        min: -maxImpactFactor,
        max: maxImpactFactor,
        axisLabel: {
          fontSize: 12
        },
        splitLine: {
          show: true
        }
      },
      series: [
        // 课程影响因子系列
        {
          name: "影响因子",
          type: "bar",
          data: values,
          barWidth: "90%",
          z: 2, // 设置更高层级
          // barGap: '-100%', // 覆盖整个区域
          itemStyle: {
            color: function (params: any) {
              return params.value > 0 ? "#5470C6" : "#EE6666";
            }
          },
          label: {
            show: false,
            position: "right",
            formatter: function (params: any) {
              const value = Math.abs(params.value).toFixed(4);
              return params.value > 0 ? `{posright|${value}}` : `{posleft|-${value}}`;
            },
            rich: {
              posright: {
                align: "left"
              },
              posleft: {
                align: "right"
              }
            }
          }
        },
        // 学期背景系列
        {
          type: "bar",
          silent: true,
          itemStyle: {
            opacity: 0.3
          },
          barGap: "-100%", // 覆盖整个区域
          barWidth: "100%",
          z: 1, // 设置更低层级
          data: courses.map((_, index) => ({
            value: maxImpactFactor, // 充满整个 0 到 maxImpactFactor 范围
            semester: semesters[index],
            itemStyle: {
              color: backgroundColors[semesterRanges.findIndex(r => index >= r.start && index <= r.end) % 2]
            }
          })),
          label: {
            show: true,
            position: "right",
            color: "rgba(0, 0, 0, 0.9)",
            fontSize: 12,
            offset: [0, 0], // 向右偏移
            formatter: (params: any) => {
              // 只在每个区间的第一个显示标签
              if (params.dataIndex === semesterRanges.find(r => r.start === params.dataIndex)?.start) {
                return semesters[params.dataIndex];
              }
              return "";
            }
          }
        },
        {
          type: "bar",
          silent: true,
          itemStyle: {
            opacity: 0.3
          },
          barGap: "-100%", // 覆盖整个区域
          barWidth: "100%",
          z: 1, // 设置更低层级
          data: courses.map((_, index) => ({
            value: -maxImpactFactor, // 充满整个 -maxImpactFactor 到 0 范围
            semester: semesters[index],
            itemStyle: {
              color: backgroundColors[semesterRanges.findIndex(r => index >= r.start && index <= r.end) % 2]
            }
          })),
          label: {
            show: false,
            position: "right",
            color: "rgba(0, 0, 0, 0.9)",
            fontSize: 12,
            offset: [0, 0], // 向右偏移
            formatter: (params: any) => {
              // 只在每个区间的第一个显示标签
              if (params.dataIndex === semesterRanges.find(r => r.start === params.dataIndex)?.start) {
                return semesters[params.dataIndex];
              }
              return "";
            }
          }
        }
      ]
    };
  };

  const personalData = ref(JSON.parse(localStorage.getItem("personal_course_data") || "{}"));
  /** 处理我的课程数据 */
  const processCourseData = computed(() => {
    const courseList: any[] = [];
    // console.log(personalData.value)
    // 遍历对象的键值对
    Object.entries(personalData.value).forEach(([key, value]) => {
      if (value && key !== "parse_crd") {
        (value as any[]).forEach(item => {
          // 计算排序键值
          // 从时间字符串中提取数字并计算sort_key
          const periodNum = parseInt(item.time.substring(3, 4));
          const isAfternoon = item.time.substring(12, 13) === "一" ? 1 : 2;
          const weekNum = parseInt(item.time.substring(8, 9));

          item.sort_key = periodNum + isAfternoon + weekNum;
          courseList.push(item);
        });
      }
    });

    // 根据sort_key排序
    return courseList.sort((a, b) => (a.sort_key || 0) - (b.sort_key || 0));
  });

  const getCourseNameByGrade = (grade: string) => {
    const courseGradeMap = {
      优秀: "优",
      良好: "良",
      中等: "中",
      及格: "及格",
      不及格: "不及格"
    };
    const myCourseData = processCourseData.value;
    const courseGrade = courseGradeMap[grade as keyof typeof courseGradeMap] || "";

    const courseGradeNumMap = {
      优: 90,
      良: 80,
      中: 70,
      及格: 60,
      不及格: 0
    };
    const courseGradeNum = courseGradeNumMap[courseGrade as keyof typeof courseGradeNumMap] || 0;
    const courses = myCourseData.filter((course: any) => {
      const numericGrade = parseInt(course.grade.replace("补", "").replace("（", "").replace("）", ""));
      return (
        course.grade === courseGrade ||
        (courseGradeNum + (courseGradeNum === 0 ? 60 : 10) > numericGrade && courseGradeNum <= numericGrade)
      );
    });
    // 按成绩排序
    const coursesSorted = courses.sort((a, b) => {
      const numericGradeA = parseInt(a.grade.replace("补", "").replace("（", "").replace("）", "")) || 0;
      const numericGradeB = parseInt(b.grade.replace("补", "").replace("（", "").replace("）", "")) || 0;
      return numericGradeB - numericGradeA;
    });

    // 构建表格式的HTML结构，提供更好的对齐效果
    if (coursesSorted.length > 0) {
      // 每行显示课程数量
      const coursesPerRow = Math.ceil(coursesSorted.length / 20);
      let htmlResult = '<table style="width:100%; border-collapse:collapse;">';

      // 按行处理课程
      for (let i = 0; i < coursesSorted.length; i += coursesPerRow) {
        htmlResult += "<tr>";

        // 添加一行中的每个课程
        for (let j = 0; j < coursesPerRow; j++) {
          const index = i + j;
          if (index < coursesSorted.length) {
            const course = coursesSorted[index];
            const teacher = courseTeacherMap[course.name] || "无";

            // 使用单元格内部的div来控制布局
            htmlResult += `
            <td style="padding:4px 8px; vertical-align:top; font-size:13px;">
              <div style="display:flex; justify-content:space-between; align-items:center; gap:3px;">
                <div style="display:flex; align-items:center; gap:2px; max-width:75%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;">
                  <span style="color:#909399;">📖</span>
                  <span style="color:#67c23a;">(${course.grade})</span>
                  <span title="${
                    course.name
                  }" style="font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;">${
              course.name
            }</span>
                </div>
                <div style="min-width:60px; text-align:right; color:#606266;">
                  ${
                    teacher != "无"
                      ? `<span style="color:#909399;">${teacher}</span>`
                      : '<span style="color:#909399;">🧑</span>'
                  }
                </div>
              </div>
            </td>`;
          } else {
            htmlResult += "<td></td>"; // 空单元格保持表格结构
          }
        }

        htmlResult += "</tr>";
      }

      htmlResult += "</table>";
      return htmlResult;
    }

    // 如果没有课程，返回空数组
    return [];
  };

  /** 处理课程成绩数据 */
  const processCoursePieData = (courses: any[]): any[] => {
    const gradeCount: Record<string, number> = {
      优秀: 0,
      良好: 0,
      中等: 0,
      及格: 0,
      不及格: 0
    };

    courses.forEach(course => {
      const level: string | null = getGradeLevel(course.grade);
      if (level) gradeCount[level]++;
    });

    return Object.entries(gradeCount)
      .filter(([_, count]) => count > 0)
      .map(([name, value]) => ({ name, value }));
  };

  /** 根据分数计算绩点 */
  const calculateGPA = (score: number, grade: string): number => {
    if (grade.includes("补")) {
      if (score >= 60) {
        return 1.0;
      } else {
        return 0.0;
      }
    }
    return score / 10 - 5 > 0 ? score / 10 - 5 : 0;
  };

  interface CourseImpact {
    学分: number;
    绩点: number;
    影响因子: number;
    说明: string;
    成绩: string;
    学期: string;
    总学分: number;
  }

  interface ImpactFactors {
    [courseName: string]: CourseImpact;
  }

  /** 处理课程绩点数据 */
  const processCourseBarData = (courses: any[]): ImpactFactors => {
    let totalCredits = 0.0;
    let totalPoints = 0.0;

    // 五级计分到百分制的映射
    const FIVE_LEVEL_TO_SCORE: { [key: string]: number } = {
      优: 95,
      良: 85,
      中: 75,
      及格: 65,
      不及格: 0
    };

    const courseDetails: Array<{
      crd: number;
      point: number;
      name: string;
      grade: string;
      course_time: string;
    }> = [];

    for (const course of courses) {
      // 使用正则表达式去除括号及其内容
      const grade = course.grade.trim().replace(/\([^)]*\)/g, "");

      // 跳过无效课程状态
      if (["未修", "在读", "", "已选"].includes(grade)) {
        continue;
      }

      let crd = parseFloat(course.crd);
      let point = 0.0;

      try {
        // 尝试解析数字成绩
        const score = parseFloat(grade);
        if (!isNaN(score)) {
          point = calculateGPA(score, grade);
        } else {
          // 处理五级计分成绩
          const convertedScore = FIVE_LEVEL_TO_SCORE[grade] || 0;
          point = calculateGPA(convertedScore, grade);
        }
      } catch (e) {
        // 处理异常情况
        point = 0.0;
      }

      // 当绩点为0时，学分不计入总学分
      if (point === 0) {
        crd = 0;
      }

      // 记录课程数据
      totalCredits += crd;
      totalPoints += crd * point;
      courseDetails.push({
        crd,
        point: Number(point.toFixed(2)), // 保留两位小数
        name: course.name,
        grade,
        course_time: course.time
      });
    }

    if (totalCredits === 0) {
      return {};
    }

    // 计算整体GPA
    const gpa = totalPoints / totalCredits;
    console.log(gpa);
    charts.value[1].title = `绩点（${gpa.toFixed(1)}）贡献度分析`;
    charts.value[3].title = `绩点（${gpa.toFixed(1)}）贡献度分析`;

    // 计算各课程影响因子
    const impactFactors: ImpactFactors = {};

    for (const detail of courseDetails) {
      const { crd, point, name, grade, course_time } = detail;
      const impact = (point - gpa) * (crd / totalCredits);
      const impactRounded = Number(impact.toFixed(4));

      let desc: string;
      if (impact > 0) {
        desc = `提升GPA +${impactRounded}`;
      } else if (impact < 0) {
        desc = `拉低GPA ${impactRounded}`;
      } else {
        desc = "无影响";
      }

      impactFactors[name] = {
        学分: crd,
        绩点: point,
        影响因子: impactRounded,
        说明: desc,
        成绩: grade,
        学期: course_time,
        总学分: totalCredits
      };
    }

    return impactFactors;
  };

  function getGradeLevel(grade: string): string | null {
    // 处理等级制成绩
    switch (grade) {
      case "优":
        return "优秀";
      case "良":
        return "良好";
      case "中":
        return "中等";
      case "及格":
        return "及格";
      case "不及格":
        return "不及格";
    }

    // 处理百分制成绩
    const numericGrade = parseInt(grade);
    if (isNaN(numericGrade)) return null; // 忽略无效成绩

    if (numericGrade >= 90) return "优秀";
    if (numericGrade >= 80) return "良好";
    if (numericGrade >= 70) return "中等";
    if (numericGrade >= 60) return "及格";
    return "不及格";
  }

  /** 初始化图表：处理数据并为每个轮播图中的图表实例化 ECharts */
  function initCharts() {
    // 销毁所有旧实例
    chartInstances.forEach(instance => instance?.dispose());
    chartInstances = [];

    const myCourseData = processCourseData.value;
    const courseGradeData = processCoursePieData(myCourseData);
    const courseBarData = processCourseBarData(myCourseData);
    console.log(courseBarData);
    charts.value[0].data = courseGradeData;
    charts.value[1].data = courseBarData;
    charts.value[2].data = courseGradeData;
    charts.value[3].data = courseBarData;

    charts.value.forEach((chart, index) => {
      const dom = chartRefs.value[index];
      if (dom) {
        const instance = echarts.init(dom);
        const option =
          index === 0 || index === 2
            ? getPieChartOption(chart.title, chart.data)
            : getBarChartOption(chart.title, chart.data);
        instance.setOption(option);
        chartInstances[index] = instance;
        window.addEventListener("resize", () => instance.resize()); // 监听窗口大小变化
      }
    });
  }

  /** 轮播图切换时调用，确保当前显示的图表自适应 */
  const handleCarouselChange = (currentIndex: number) => {
    // console.log(chartInstances)
    if (chartInstances[currentIndex]) {
      chartInstances[currentIndex].resize();
    }
  };

  const avatarSrc = computed(() => {
    return `data:image/svg+xml;utf8,${encodeURIComponent(multiavatar(localStorage.getItem("token") || ""))}`;
  });

  // 登录表单
  const loginForm = ref({
    studentId: localStorage.getItem("studentId") || "",
    password: "",
    remember: localStorage.getItem("rememberMe") === "true",
    hardUpdate: false
  });

  const updateDialogVisible = ref(false);
  const mainDialogVisible = ref(false);

  // 设置个人课程数据
  const setPersonalCourseData = async () => {
    if (loginForm.value.hardUpdate && !loginForm.value.password) {
      ElMessage.error("请输入密码");
      return;
    }
    if (JSON.stringify(personalData.value) === "{}" || loginForm.value.hardUpdate) {
      // 全局遮罩加载
      const loading = ElLoading.service({
        lock: true,
        text: "加载中...",
        background: "rgba(0, 0, 0, 0.7)"
      });
      try {
        const response = await api.getPersonalCourseData(
          localStorage.getItem("userId"),
          loginForm.value.studentId,
          loginForm.value.password || decrypt(localStorage.getItem("studentPw") || ""),
          loginForm.value.hardUpdate
        );
        console.log(response.data);
        personalData.value = response.data;
        localStorage.setItem("personal_course_data", JSON.stringify(personalData.value));
        ElMessage.success("获取成绩数据成功");
        updateDialogVisible.value = false;

        if (loginForm.value.remember && loginForm.value.password) {
          localStorage.setItem("studentId", loginForm.value.studentId);
          localStorage.setItem("studentPw", encrypt(loginForm.value.password));
          localStorage.setItem("rememberMe", loginForm.value.remember.toString());
        }

        await nextTick();
        initCharts();
      } catch (error) {
        mainDialogVisible.value = true;
        updateDialogVisible.value = true;
        loginForm.value.hardUpdate = true;
      } finally {
        loading.close();
      }
    }
  };

  // 处理数据更新
  const handleUpdate = () => {
    console.log(loginForm.value);
    // 表单验证
    // 这里添加实际的数据更新逻辑
    localStorage.removeItem("personal_course_data");
    if (loginForm.value.remember && loginForm.value.password) {
      localStorage.setItem("studentPw", encrypt(loginForm.value.password));
      localStorage.setItem("rememberMe", "true");
    } else {
      localStorage.removeItem("studentPw");
      localStorage.removeItem("rememberMe");
    }
    setPersonalCourseData();
  };

  // 显示更新对话框
  const showUpdateDialog = () => {
    // 读取保存的登录信息
    if (localStorage.getItem("rememberMe") === "true") {
      loginForm.value = {
        studentId: localStorage.getItem("studentId") || "",
        password: localStorage.getItem("studentPw") ? decrypt(localStorage.getItem("studentPw") || "") : "",
        remember: localStorage.getItem("rememberMe") === "true",
        hardUpdate: false
      };
    }
    updateDialogVisible.value = true;
    console.log(loginForm.value);
  };
  const selectedTerm = ref("all");
  // 获取唯一学期列表
  const uniqueTerms = computed(() => {
    const terms = new Set();
    // 如果rawData.value为空，则返回空数组
    if (JSON.stringify(personalData.value) === "{}") {
      return [];
    }
    Object.values(personalData.value).forEach((courses: any) => {
      if (Array.isArray(courses)) {
        courses.forEach((c: any) => terms.add(c.time));
      }
    });
    return Array.from(terms).sort();
  });
  // 过滤后的课程数据
  const filteredCourses = computed(() => {
    const result: any = {};
    // 如果rawData.value为空，则返回空对象
    if (JSON.stringify(personalData.value) === "{}") {
      return {};
    }
    Object.entries(personalData.value).forEach(([type, courses]: any) => {
      if (type !== "parse_crd") {
        result[type] = courses.filter((c: any) => selectedTerm.value === "all" || c.time === selectedTerm.value);
      }
    });
    return result;
  });
  // 类型映射
  const typeMap: Record<string, string> = {
    bixiu: "必修课程",
    xuanxiu: "选修课程",
    zxianxuan: "专项选修"
  };
  // 表格行样式
  const tableRowClassName = ({ rowIndex }: any) => {
    return rowIndex % 2 === 0 ? "even-row" : "odd-row";
  };
  // 处理成绩颜色
  const gradeClass = (grade: string) => {
    // console.log(grade)
    const scoreMap = {
      优: "grade-excellent",
      良: "grade-good",
      中: "grade-medium",
      及格: "grade-pass",
      不及格: "grade-fail"
    };

    // 如果成绩是数字，进行比较
    if (!isNaN(Number(grade))) {
      const numericGrade = Number(grade);
      if (numericGrade >= 90) return "grade-excellent";
      if (numericGrade >= 80) return "grade-good";
      if (numericGrade >= 60) return "grade-medium";
      return "grade-fail";
    } else if (grade.includes("补")) return "grade-fail";
    else if (grade === "在读") return "grade-excellent";
    else if (grade === "未修") return "grade-medium";
    return scoreMap[grade as keyof typeof scoreMap] || "";
  };

  // 在读课程列表 - 不要直接引用 processCourseData.value
  const readingCourses = ref<any[]>([]);
  const tempCourseData = ref<any[]>([]);
  const gpaDialogVisible = ref(false);
  const tempGPA = ref(0);
  const oldGPA = ref(0);

  // 监听对话框打开事件，每次打开时重新初始化数据
  watch(gpaDialogVisible, newVal => {
    if (newVal) {
      refreshGPA();
    }
  });

  const refreshGPA = () => {
    // 使用深拷贝来重新初始化数据，避免引用原始数据
    const courseData = JSON.parse(JSON.stringify(processCourseData.value));

    // 过滤在读或未修的课程
    readingCourses.value = courseData.filter((c: any) => c.grade === "在读" || c.grade === "未修");

    //排序 先在读 后未修
    readingCourses.value.sort((a, b) => {
      if (a.grade === "在读" && b.grade === "未修") return -1;
      if (a.grade === "未修" && b.grade === "在读") return 1;
      return 0;
    });
    console.log(courseData.value);

    // 设置临时课程数据（用于计算GPA）
    tempCourseData.value = JSON.parse(JSON.stringify(courseData));

    // 计算原始GPA并存储
    let totalCredits = 0.0;
    let totalPoints = 0.0;

    // 五级计分到百分制的映射
    const FIVE_LEVEL_TO_SCORE: { [key: string]: number } = {
      优: 95,
      良: 85,
      中: 75,
      及格: 60,
      不及格: 0
    };

    const courseDetails: Array<{
      crd: number;
      point: number;
      name: string;
      grade: string;
      course_time: string;
    }> = [];

    for (const course of tempCourseData.value) {
      // 使用正则表达式去除括号及其内容
      const grade = course.grade.trim().replace(/\([^)]*\)/g, "");

      // 跳过无效课程状态
      if (["未修", "在读", "", "已选"].includes(grade)) {
        continue;
      }

      let crd = parseFloat(course.crd);
      let point = 0.0;

      try {
        // 尝试解析数字成绩
        const score = parseFloat(grade);
        if (!isNaN(score)) {
          point = calculateGPA(score, grade);
        } else {
          // 处理五级计分成绩
          const convertedScore = FIVE_LEVEL_TO_SCORE[grade] || 0;
          point = calculateGPA(convertedScore, grade);
        }
      } catch (e) {
        // 处理异常情况
        point = 0.0;
      }

      // 当绩点为0时，学分不计入总学分
      if (point === 0) {
        crd = 0;
      }

      // 记录课程数据
      totalCredits += crd;
      totalPoints += crd * point;
      courseDetails.push({
        crd,
        point: Number(point.toFixed(2)), // 保留两位小数
        name: course.name,
        grade,
        course_time: course.time
      });
    }

    if (totalCredits === 0) {
      return {};
    }

    if (totalCredits > 0) {
      // 计算并保存原始GPA
      oldGPA.value = Number((totalPoints / totalCredits).toFixed(2));
    } else {
      oldGPA.value = 0;
    }

    // 初始时tempGPA与oldGPA相同
    tempGPA.value = oldGPA.value;
  };

  // 计算GPA
  const updateTempGPA = computed(() => {
    // ElMessage.success('计算GPA')
    tempCourseData.value.forEach((c: any) => {
      const course = readingCourses.value.find((r: any) => r.name === c.name);
      if (course) {
        c.grade = course.grade;
      }
    });
    let totalCredits = 0.0;
    let totalPoints = 0.0;

    // 五级计分到百分制的映射
    const FIVE_LEVEL_TO_SCORE: { [key: string]: number } = {
      优: 95,
      良: 85,
      中: 75,
      及格: 60,
      不及格: 0
    };

    const courseDetails: Array<{
      crd: number;
      point: number;
      name: string;
      grade: string;
      course_time: string;
    }> = [];

    for (const course of tempCourseData.value) {
      // 使用正则表达式去除括号及其内容
      const grade = course.grade.trim().replace(/\([^)]*\)/g, "");

      // 跳过无效课程状态
      if (["未修", "在读", "", "已选"].includes(grade)) {
        continue;
      }

      let crd = parseFloat(course.crd);
      let point = 0.0;

      try {
        // 尝试解析数字成绩
        const score = parseFloat(grade);
        if (!isNaN(score)) {
          point = calculateGPA(score, grade);
        } else {
          // 处理五级计分成绩
          const convertedScore = FIVE_LEVEL_TO_SCORE[grade] || 0;
          point = calculateGPA(convertedScore, grade);
        }
      } catch (e) {
        // 处理异常情况
        point = 0.0;
      }

      // 当绩点为0时，学分不计入总学分
      if (point === 0) {
        crd = 0;
      }

      // 记录课程数据
      totalCredits += crd;
      totalPoints += crd * point;
      courseDetails.push({
        crd,
        point: Number(point.toFixed(2)), // 保留两位小数
        name: course.name,
        grade,
        course_time: course.time
      });
    }

    if (totalCredits === 0) {
      return {};
    }

    // 计算整体GPA
    const gpa = totalPoints / totalCredits;
    tempGPA.value = Number(gpa.toFixed(2));
  });

  // 计算剩余选修学分
  const calculateRemainCrd = computed(() => {
    const totalCrd = parseFloat(personalData.value?.parse_crd?.total_crd) || 0;
    const earnedCrd = parseFloat(personalData.value?.parse_crd?.earned_crd) || 0;
    const studyingCrd = parseFloat(personalData.value?.parse_crd?.studying_crd) || 0;

    return Math.max(0, totalCrd - earnedCrd - studyingCrd - unstudiedCredits.value);
  });

  // 已获得学分
  const obtainedCredits = computed(() => {
    const obtainedCourses = processCourseData.value.map((c: any) => {
      const grade = c.grade.trim().replace(/\([^)]*\)/g, "");
      const scores = ["优", "良", "中", "及格", "不及格"];
      if (scores.includes(grade) || parseFloat(grade) >= 60) {
        return parseFloat(c.crd);
      }
      return 0;
    });
    console.log(obtainedCourses.reduce((acc, course) => acc + course, 0));
    return obtainedCourses.reduce((acc, course) => acc + course, 0);
  });

  // 挂科学分
  const failedCredits = computed(() => {
    const failedCourses = processCourseData.value.map((c: any) => {
      const grade = c.grade.trim().replace(/\([^)]*\)/g, "");
      if (grade === "不及格" || parseFloat(grade) < 60) {
        return parseFloat(c.crd);
      }
      return 0;
    });
    console.log(failedCourses.reduce((acc, course) => acc + course, 0));
    return failedCourses.reduce((acc, course) => acc + course, 0);
  });

  // 未修学分
  const unstudiedCredits = computed(() => {
    const unstudiedCourses = processCourseData.value.map((c: any) => {
      const grade = c.grade.trim().replace(/\([^)]*\)/g, "");
      if (grade === "未修") {
        return parseFloat(c.crd);
      }
      return 0;
    });
    console.log(unstudiedCourses.reduce((acc, course) => acc + course, 0));
    return unstudiedCourses.reduce((acc, course) => acc + course, 0);
  });

  // 获取学期分组
  const getSemesterGroups = () => {
    const semesters = new Set<string>();
    readingCourses.value.forEach(course => {
      if (course.time) {
        semesters.add(course.time);
      }
    });
    console.log(readingCourses.value);
    return Array.from(semesters).sort();
  };

  // 获取特定学期的课程
  const getSemesterCourses = (semester: string) => {
    return readingCourses.value.filter(course => course.time === semester);
  };

  onMounted(async () => {
    if (JSON.stringify(personalData.value) !== "{}") {
      await nextTick();
      initCharts();
    } else {
      // ElMessage.error('暂无课程数据，请先绑定MySeig系统')
      updateDialogVisible.value = true;
    }
    console.log(personalData.value);

    getData();
    getGreeting();
    setPersonalCourseData();
  });

  onBeforeUnmount(() => {
    console.log("Charts 数组长度:", charts.value.length); // 应为 2
    // 销毁所有图表实例，释放资源
    chartInstances.forEach(instance => {
      if (instance) instance.dispose();
    });
    // 如有注册 window resize 事件，实际项目中建议保存事件函数引用后注销
  });

  // 添加处理日期点击的函数
  function handleDateClick(date: Date) {
    selectedDate.value = date;
    weekDays.value = generateWeekDays(); // 更新周日期显示
    loadSelectedDateCourses();
  }

  // 添加重置到今天的函数
  function resetToToday() {
    selectedDate.value = new Date(today);
    weekDays.value = generateWeekDays();
    loadSelectedDateCourses();
  }

  // 添加加载选中日期课程的函数
  function loadSelectedDateCourses() {
    if (tableData.value.length > 0) {
      const now_table = tableData.value.filter(
        (item: any) =>
          item.year_term.year === year_term.value.year && item.year_term.semester === year_term.value.semester
      );
      if (now_table.length > 0) {
        todayCourses.value = getTodayCourses2(selectedDate.value, now_table[0]);
      }
    }
  }
</script>

<style scoped>
  .container {
    height: 90vh;
    display: flex;
    flex-direction: column;
    background: #f0f2f5;
  }

  .top-card {
    margin: 10px;
  }
  :deep(.el-card__body) {
    padding: 20px;
  }

  .top-content {
    display: flex;
    justify-content: space-between;
    align-items: center;
  }

  .user-info {
    display: flex;
    align-items: center;
  }

  .avatar {
    width: 80px;
    height: 80px;
    border-radius: 50%;
    margin-right: 20px;
  }

  .welcome-text {
    line-height: 1.5;
    /* margin-left: 0px; */
  }

  .username {
    font-size: 20px;
    font-weight: bold;
    margin-bottom: 5px;
  }

  .stats {
    display: flex;
    gap: 40px;
    margin-right: 40px;
  }

  .stat-item {
    text-align: center;
  }

  .value {
    font-size: 24px;
    font-weight: bold;
    color: #409eff;
  }

  .label {
    color: #666;
  }

  .main-content {
    flex: 1;
    display: flex;
    gap: 10px;
    padding: 0 10px 10px 10px;
    overflow: hidden;
  }

  .left-side {
    width: 30%;
    min-width: 350px;
    display: flex;
    flex-direction: column;
    gap: 10px;
  }

  .right-side {
    flex: 1;
    /* height: calc(100vh - 246px); */
  }

  .message-box {
    flex: 1;
  }
  :deep(.el-card__body) {
    padding: 15px;
  }

  .message-header {
    display: flex;
    justify-content: space-between;
    margin-bottom: 15px;
  }

  .message-list {
    height: 200px;
    overflow-y: auto;
    /* 隐藏滚动条 */
    -ms-overflow-style: none; /* IE 和 Edge */
    scrollbar-width: none; /* Firefox */

    &::-webkit-scrollbar {
      display: none; /* Chrome, Safari 和 Opera */
    }
  }

  .message-item {
    padding: 10px;
    margin: 5px 0;
    background: #f8f9fa;
    border-radius: 4px;
  }

  .calendar-box {
    flex: 2;
  }
  :deep(.el-card__body) {
    padding: 15px;
  }

  .week-days {
    display: flex;
    justify-content: space-between;
    /* margin: 15px 0; */
  }

  .day {
    flex: 1;
    text-align: center;
    padding: 10px;
    border-radius: 4px;
    border: 1px solid #ccc;
    transition: all 0.2s;
  }

  .day:hover {
    background: #e8f4ff;
    border-color: #a3d0ff;
  }

  .day.today {
    background: #f0f4ff;
    border: 1px solid #409eff;
  }

  .day.selected {
    background: #409eff;
    border: 1px solid #409eff;
    color: white;
  }

  .current-date {
    cursor: pointer;
    transition: color 0.2s;
    justify-content: center;
    align-items: center;
    display: flex;
  }

  .current-date:hover {
    color: #409eff;
  }

  .course-tag {
    display: block;
    font-size: 12px;
    background: #e1f3d8;
    margin: 2px;
    padding: 2px 5px;
    border-radius: 3px;
  }

  .today-schedule {
    /* margin-top: 15px; */
    max-height: 85%;
    overflow-y: auto;
    /* 隐藏滚动条 */
    -ms-overflow-style: none; /* IE 和 Edge */
    scrollbar-width: none; /* Firefox */

    &::-webkit-scrollbar {
      display: none; /* Chrome, Safari 和 Opera */
    }
  }

  .schedule-item {
    display: flex;
    justify-content: space-between;
    padding: 8px;
    margin: 5px 0;
    background: #f8f9fa;
    border-radius: 4px;
  }

  .chart-carousel {
    height: 100%;
  }
  :deep(.el-carousel__container) {
    height: 100% !important;
  }

  .chart-card {
    height: 100%;
  }
  :deep(.el-card__body) {
    height: calc(100% - 40px);
    padding: 20px;
  }

  .chart-container {
    height: 100%;
  }

  /* 弹窗 */
  .dialog-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
  .filter-container {
    margin-bottom: 20px;
  }
  .table-container {
    max-height: 60vh;
    overflow-y: auto;
    /* 禁止选中 */
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
  }

  .group-title {
    position: sticky;
    top: 0;
    background: #fff;
    z-index: 2;
    margin: 0;
    padding: 10px 0;
    color: #409eff;
  }

  .grade-excellent {
    color: #67c23a;
  }
  .grade-good {
    color: #e6a23c;
  }
  .grade-medium {
    color: #909399;
  }
  .grade-pass {
    color: #409eff;
  }
  .grade-fail {
    color: #f56c6c;
  }

  .gpa-container {
    padding: 20px;
  }

  .course-list {
    max-height: 300px;
    overflow-y: auto;
    margin-bottom: 20px;
    padding: 10px;
    border-radius: 8px;
    background-color: #f8f9fa;
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.1);
  }

  .semester-group {
    margin-bottom: 15px;
    padding: 10px;
  }

  .semester-header {
    text-align: center;
    font-size: 14px;
    font-weight: bold;
    color: #606266;
    padding: 8px 0;
    margin-bottom: 8px;
    /* border-bottom: 1px solid #dcdfe6;
  position: sticky; */
    top: 0;
    background-color: #f8f9fa;
    z-index: 1;
  }

  .course-item {
    display: flex;
    align-items: center;
    margin-bottom: 12px;
    padding: 12px;
    border-radius: 8px;
    background-color: white;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
    transition: all 0.3s ease;
  }

  .course-item:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
  }

  .course-info {
    flex: 1;
    display: flex;
    align-items: center;
    gap: 10px;
  }

  .course-name {
    flex: 1;
    font-weight: bold;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    margin: 0 10px;
  }

  .course-credit {
    font-size: 12px;
  }

  .course-input {
    width: 120px;
    margin-left: 10px;
  }

  .gpa-value {
    text-align: center;
    font-size: 24px;
    font-weight: bold;
    color: #409eff;
    margin: 20px 0;
    padding: 15px;
    border-radius: 8px;
    background-color: #ecf5ff;
  }

  .gpa-change {
    margin-left: 10px;
    font-size: 14px;
    font-weight: normal;
  }

  .gpa-up {
    color: #67c23a; /* 绿色 */
  }

  .gpa-down {
    color: #f56c6c; /* 红色 */
  }

  /* 学分公式展示样式 */
  .credit-container {
    margin-top: -20px;
    padding: 15px;
    border-radius: 8px;
    background-color: #f8f9fa;
  }

  .credit-formula {
    display: flex;
    flex-direction: column;
    align-items: center;
  }

  .formula-title {
    font-size: 18px;
    font-weight: bold;
    margin-bottom: 15px;
    color: #303133;
  }

  .formula-content {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    padding: 15px;
    background-color: #fff;
    border-radius: 8px;
    box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
    width: 90%;
    margin: 0 auto;
  }

  .formula-item {
    font-size: 18px;
    font-weight: 700;
    padding: 8px 15px;
    border-radius: 6px;
    margin: 0 5px;
    cursor: default;
    transition: transform 0.2s, box-shadow 0.2s;
  }

  .formula-item:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  }

  .total-crd {
    color: #409eff;
    background-color: rgba(64, 158, 255, 0.15);
    border: 1px solid rgba(64, 158, 255, 0.3);
  }

  .earned-crd {
    color: #67c23a;
    background-color: rgba(103, 194, 58, 0.15);
    border: 1px solid rgba(103, 194, 58, 0.3);
  }

  .studying-crd {
    color: #e6a23c;
    background-color: rgba(230, 162, 60, 0.15);
    border: 1px solid rgba(230, 162, 60, 0.3);
  }

  .notrepaired-crd {
    color: #e63ce6;
    background-color: rgba(230, 58, 230, 0.15);
    border: 1px solid rgba(230, 58, 230, 0.3);
  }

  .remain-crd {
    color: #f56c6c;
    background-color: rgba(245, 108, 108, 0.15);
    border: 1px solid rgba(245, 108, 108, 0.3);
  }

  .formula-operator {
    font-size: 26px;
    font-weight: bold;
    margin: 0 8px;
    color: #606266;
  }

  .tooltip-formula {
    padding: 8px;
    font-size: 14px;
  }

  .sub-formula {
    margin-top: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
  }

  .earned {
    color: #67c23a;
    font-weight: bold;
    font-size: 16px;
  }

  .passed {
    color: #409eff;
    font-weight: bold;
    font-size: 16px;
  }

  .failed {
    color: #f56c6c;
    font-weight: bold;
    font-size: 16px;
  }

  .progress-bar {
    width: 90%;
    margin-top: 20px;
  }

  .progress-label {
    font-size: 14px;
    margin-bottom: 10px;
    color: #606266;
    text-align: left;
  }

  .declaration-content {
    .declaration-section {
      margin-bottom: 15px;

      &:last-child {
        margin-bottom: 0;
      }

      h4 {
        margin: 0 0 8px 0;
        font-size: 14px;
        color: #303133;
        font-weight: 600;
      }

      ol {
        margin: 0;
        padding-left: 20px;

        li {
          margin-bottom: 8px;
          line-height: 1.5;
          font-size: 13px;
          color: #606266;

          &:last-child {
            margin-bottom: 0;
          }

          ul {
            margin: 4px 0 0 0;
            padding-left: 20px;

            li {
              margin-bottom: 2px;
            }
          }
        }
      }

      p {
        margin: 0;
        line-height: 1.5;
        font-size: 13px;
        color: #606266;
      }

      .highlight {
        color: #409eff;
        font-weight: 500;
      }
    }
  }
</style>
